﻿#region

using System;
using System.Collections.Generic;
using EsbMonitorExtension.MonitorTasks.Base;
using EsbMonitorMessages.Domain;
using EsbMonitorMessages.Events;
using log4net;
using NServiceBus;
using NServiceBus.Unicast;

#endregion

namespace EsbMonitorExtension.MonitorTasks
{
    public class HandlerStartedTask : BaseMonitorTask
    {
        private static readonly ILog Logger = LogManager.GetLogger(typeof (HandlerStartedTask));


        public HandlerStartedTask(IUnicastBus bus)
            : base(bus)
        {
        }

        public override void RunTask()
        {
            Logger.Info("Running HandlerStartedTask");

            UnicastBus unicastBus = (UnicastBus) Bus;

            foreach (Type messageHandlerType in unicastBus.MessageHandlerTypes)
            {
                InspectHandlerType(messageHandlerType);
            }

            Logger.Info("Finished HandlerStartedTask");
        }

        private void InspectHandlerType(Type messageHandlerType)
        {
            foreach (Type type in GetMessageTypesIfIsMessageHandler(messageHandlerType))
            {
                Logger.Info("Found handler of messages of type " + type);

                RaiseHandlerStartedEvent(new TypeInfo(type), Bus.ServiceInfo());
            }
        }


        private IEnumerable<Type> GetMessageTypesIfIsMessageHandler(Type type)
        {
            foreach (var t in type.GetInterfaces())
            {
                if (t.IsGenericType)
                {
                    var args = t.GetGenericArguments();
                    if (args.Length != 1)
                    {
                        continue;
                    }

                    if (!typeof (IMessage).IsAssignableFrom(args[0]))
                    {
                        continue;
                    }

                    var handlerType = typeof (IMessageHandler<>).MakeGenericType(args[0]);
                    if (handlerType.IsAssignableFrom(t))
                    {
                        yield return args[0];
                    }
                }
            }
        }

        private void RaiseHandlerStartedEvent(TypeInfo handledTypeInfo, ServiceInfo serviceInfo)
        {
            Bus.Send<IHandlerStarted>(m =>
                                          {
                                              m.ServiceInfo = serviceInfo;
                                              m.HandledType = handledTypeInfo;
                                              m.EventTime = DateTime.Now;
                                          });
        }
    }
}